using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
namespace Microsoft.Phone.Controls.Primitives
{
	[StyleTypedProperty(Property = "ItemContainerStyle", StyleTargetType = typeof(PivotHeaderItem)), TemplatePart(Name = "Canvas", Type = typeof(Canvas))]
	public class PivotHeadersControl : TemplatedItemsControl<PivotHeaderItem>
	{
		private class AnimationInstruction
		{
			public int _previousIndex;
			public int _index;
			public IEasingFunction _ease;
			public double _width;
			public double _durationInSeconds;
			public AnimationInstruction(int previous, int next)
			{
				this._previousIndex = previous;
				this._index = next;
			}
		}
		private const string CanvasName = "Canvas";
		private const double PivotSeconds = 0.5;
		private bool _isDesign;
		private Canvas _canvas;
		private Dictionary<Control, double> _sizes;
		private Dictionary<Control, TranslateTransform> _translations;
		private Dictionary<Control, OpacityAnimator> _opacities;
		private Image _leftMirror;
		private TranslateTransform _leftMirrorTranslation;
		private TransformAnimator _canvasAnimator;
		internal readonly IEasingFunction QuarticEase = new QuarticEase();
		internal bool _cancelClick;
		private bool _activeSelectionChange;
		private bool _isAnimating;
		private Queue<PivotHeadersControl.AnimationInstruction> _queuedAnimations;
		internal bool _wasClicked;
		private Pivot _pivot;
		private double _animatingWidth;
		private DateTime _currentItemAnimationStarted;
		internal static readonly DependencyProperty SelectedIndexProperty = DependencyProperty.Register("SelectedIndex", typeof(int), typeof(PivotHeadersControl), new PropertyMetadata(0, new PropertyChangedCallback(PivotHeadersControl.OnSelectedIndexPropertyChanged)));
		public static readonly DependencyProperty VisualFirstIndexProperty = DependencyProperty.Register("VisualFirstIndex", typeof(int), typeof(PivotHeadersControl), new PropertyMetadata(0, new PropertyChangedCallback(PivotHeadersControl.OnVisualFirstIndexPropertyChanged)));
		private bool _ignorePropertyChange;
		private int _previousVisualFirstIndex;
		internal event EventHandler<SelectedIndexChangedEventArgs> SelectedIndexChanged
		{
			[MethodImpl(32)]
			add
			{
				this.SelectedIndexChanged = (EventHandler<SelectedIndexChangedEventArgs>)Delegate.Combine(this.SelectedIndexChanged, value);
			}
			[MethodImpl(32)]
			remove
			{
				this.SelectedIndexChanged = (EventHandler<SelectedIndexChangedEventArgs>)Delegate.Remove(this.SelectedIndexChanged, value);
			}
		}
		internal int SelectedIndex
		{
			get
			{
				return (int)base.GetValue(PivotHeadersControl.SelectedIndexProperty);
			}
			set
			{
				base.SetValue(PivotHeadersControl.SelectedIndexProperty, value);
			}
		}
		public int VisualFirstIndex
		{
			get
			{
				return (int)base.GetValue(PivotHeadersControl.VisualFirstIndexProperty);
			}
			set
			{
				base.SetValue(PivotHeadersControl.VisualFirstIndexProperty, value);
			}
		}
		internal AnimationDirection AnimationDirection
		{
			get;
			set;
		}
		protected override Size ArrangeOverride(Size finalSize)
		{
			PerfLog.BeginLogMarker(PerfMarkerEvents.MPC_PIVOT_ARRANGE, PerfLog.PivotHeadersControl);
			Size result = base.ArrangeOverride(finalSize);
			PerfLog.EndLogMarker(PerfMarkerEvents.MPC_PIVOT_ARRANGE, PerfLog.PivotHeadersControl);
			return result;
		}
		protected override Size MeasureOverride(Size availableSize)
		{
			PerfLog.BeginLogMarker(PerfMarkerEvents.MPC_PIVOT_MEASURE, PerfLog.PivotHeadersControl);
			Size result = base.MeasureOverride(availableSize);
			PerfLog.EndLogMarker(PerfMarkerEvents.MPC_PIVOT_MEASURE, PerfLog.PivotHeadersControl);
			return result;
		}
		private static void OnSelectedIndexPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
		{
			PivotHeadersControl pivotHeadersControl = d as PivotHeadersControl;
			int index = (int)e.get_NewValue();
			int previousIndex = (int)e.get_OldValue();
			if (!pivotHeadersControl._activeSelectionChange)
			{
				pivotHeadersControl.SelectOne(previousIndex, index);
			}
		}
		private static void OnVisualFirstIndexPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
		{
			PivotHeadersControl pivotHeadersControl = d as PivotHeadersControl;
			if (pivotHeadersControl._ignorePropertyChange)
			{
				pivotHeadersControl._ignorePropertyChange = false;
				return;
			}
			int num = (int)e.get_NewValue();
			pivotHeadersControl._previousVisualFirstIndex = (int)e.get_OldValue();
			int count = pivotHeadersControl.get_Items().get_Count();
			if (count > 0 && num >= count)
			{
				pivotHeadersControl._ignorePropertyChange = true;
				d.SetValue(e.get_Property(), 0);
			}
			pivotHeadersControl.UpdateItemsLayout();
		}
		public PivotHeadersControl()
		{
			PerfLog.BeginLogMarker(PerfMarkerEvents.MPC_PIVOT_STARTUP, PerfLog.PivotHeadersControl);
			base.set_DefaultStyleKey(typeof(PivotHeadersControl));
			this._leftMirror = new Image();
			this._leftMirror.set_CacheMode(new BitmapCache());
			this._sizes = new Dictionary<Control, double>();
			this._translations = new Dictionary<Control, TranslateTransform>();
			this._opacities = new Dictionary<Control, OpacityAnimator>();
			this._isDesign = DesignerProperties.get_IsInDesignTool();
			this._queuedAnimations = new Queue<PivotHeadersControl.AnimationInstruction>();
			base.add_Loaded(new RoutedEventHandler(this.PivotHeadersControl_Loaded));
		}
		private void PivotHeadersControl_Loaded(object sender, RoutedEventArgs e)
		{
			base.remove_Loaded(new RoutedEventHandler(this.PivotHeadersControl_Loaded));
			PerfLog.EndLogMarker(PerfMarkerEvents.MPC_PIVOT_STARTUP, PerfLog.PanoramaItem);
		}
		public override void OnApplyTemplate()
		{
			PerfLog.BeginLogMarker(PerfMarkerEvents.MPC_PIVOT_APPLYTEMPLATE, PerfLog.PivotHeadersControl);
			this._pivot = null;
			if (this._canvas != null)
			{
				this._canvas.get_Children().Remove(this._leftMirror);
				this._leftMirror = null;
			}
			base.OnApplyTemplate();
			this._canvas = (base.GetTemplateChild("Canvas") as Canvas);
			if (this._canvas != null)
			{
				this._canvas.get_Children().Add(this._leftMirror);
				this._leftMirrorTranslation = TransformAnimator.GetTranslateTransform(this._leftMirror);
				if (!double.IsNaN(this._leftMirror.get_ActualWidth()) && this._leftMirror.get_ActualWidth() > 0.0)
				{
					this._leftMirrorTranslation.set_X(-this._leftMirror.get_ActualWidth());
				}
			}
			if (base.get_Items().get_Count() > 0)
			{
				this.VisualFirstIndex = this.SelectedIndex;
			}
			DependencyObject dependencyObject = this;
			do
			{
				dependencyObject = VisualTreeHelper.GetParent(dependencyObject);
				this._pivot = (dependencyObject as Pivot);
			}
			while (this._pivot == null && dependencyObject != null);
			if (this._pivot != null)
			{
				this._pivot._clickedHeadersControl = this;
			}
			PerfLog.EndLogMarker(PerfMarkerEvents.MPC_PIVOT_APPLYTEMPLATE, PerfLog.PivotHeadersControl);
		}
		protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e)
		{
			base.OnItemsChanged(e);
			if (base.get_Items().get_Count() > 0)
			{
				this.UpdateItemsLayout();
				return;
			}
			this.VisualFirstIndex = 0;
			this.SelectedIndex = 0;
		}
		protected override void ClearContainerForItemOverride(DependencyObject element, object item)
		{
			base.ClearContainerForItemOverride(element, item);
			PivotHeaderItem pivotHeaderItem = (PivotHeaderItem)element;
			pivotHeaderItem.ParentHeadersControl = null;
			pivotHeaderItem.Item = null;
			if (!object.ReferenceEquals(element, item))
			{
				pivotHeaderItem.Item = item;
			}
			Control control = item as Control;
			if (control != null)
			{
				control.remove_SizeChanged(new SizeChangedEventHandler(this.OnHeaderSizeChanged));
				this._sizes.Remove(control);
				this._translations.Remove(control);
			}
		}
		protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
		{
			base.PrepareContainerForItemOverride(element, item);
			PivotHeaderItem pivotHeaderItem = (PivotHeaderItem)element;
			pivotHeaderItem.ParentHeadersControl = this;
			int num = base.get_ItemContainerGenerator().IndexFromContainer(element);
			if (num != -1)
			{
				pivotHeaderItem.IsSelected = (this.SelectedIndex == num);
			}
			Control control = item as Control;
			if (control != null)
			{
				control.add_SizeChanged(new SizeChangedEventHandler(this.OnHeaderSizeChanged));
			}
		}
		private void OnHeaderSizeChanged(object sender, SizeChangedEventArgs e)
		{
			double width = e.get_NewSize().get_Width();
			double height = e.get_NewSize().get_Height();
			if (double.IsNaN(base.get_Height()) || height > base.get_Height())
			{
				base.set_Height(height);
			}
			this._sizes.set_Item((Control)sender, width);
			this.UpdateItemsLayout();
			if (this._leftMirrorTranslation.get_X() == 0.0)
			{
				this.UpdateLeftMirrorImage(this.SelectedIndex);
			}
		}
		internal void OnHeaderItemClicked(PivotHeaderItem item)
		{
			if (!this._isAnimating)
			{
				if (this._cancelClick)
				{
					this._cancelClick = false;
					return;
				}
				this._wasClicked = true;
				item.IsSelected = true;
			}
		}
		internal void NotifyHeaderItemSelected(PivotHeaderItem item, bool isSelected)
		{
			if (isSelected)
			{
				int num = base.get_ItemContainerGenerator().IndexFromContainer(item);
				int selectedIndex = this.SelectedIndex;
				this.SelectOne(selectedIndex, num);
				this.SelectedIndex = num;
			}
		}
		private void SelectOne(int previousIndex, int index)
		{
			if (!this._activeSelectionChange)
			{
				this.UpdateLeftMirrorImage(index);
				if (index >= 0 && index < base.get_Items().get_Count())
				{
					try
					{
						this._activeSelectionChange = true;
						for (int i = 0; i < base.get_Items().get_Count(); i++)
						{
							PivotHeaderItem pivotHeaderItem = (PivotHeaderItem)base.get_ItemContainerGenerator().ContainerFromIndex(i);
							if (pivotHeaderItem != null)
							{
								pivotHeaderItem.IsSelected = (index == i);
							}
						}
					}
					finally
					{
						SafeRaise.Raise<SelectedIndexChangedEventArgs>(this.SelectedIndexChanged, this, new SelectedIndexChangedEventArgs(index));
						this._activeSelectionChange = false;
						this.BeginAnimate(previousIndex, index);
					}
				}
			}
		}
		internal void RestoreHeaderPosition(Duration duration)
		{
			if (this._canvas != null && !this._isAnimating)
			{
				TransformAnimator.EnsureAnimator(this._canvas, ref this._canvasAnimator);
				if (this._canvasAnimator != null)
				{
					this._canvasAnimator.GoTo(0.0, duration);
				}
			}
		}
		internal void PanHeader(double cumulative, double contentWidth, Duration duration)
		{
			if (!this._isAnimating && this._canvas != null)
			{
				TransformAnimator.EnsureAnimator(this._canvas, ref this._canvasAnimator);
				if (this._canvasAnimator != null)
				{
					double num = (cumulative < 0.0) ? this.GetItemWidth(this.SelectedIndex) : this.GetLeftMirrorWidth(this.SelectedIndex);
					this._canvasAnimator.GoTo(cumulative / contentWidth * num, duration);
				}
			}
		}
		private void BeginAnimate(int previousIndex, int newIndex)
		{
			if (!this._isDesign && this._canvas != null)
			{
				if ((newIndex != this.RollingIncrement(previousIndex) && newIndex != this.RollingDecrement(previousIndex)) || this._wasClicked)
				{
					this._wasClicked = false;
					int num2;
					for (int num = previousIndex; num != newIndex; num = num2)
					{
						num2 = this.RollingIncrement(num);
						PivotHeadersControl.AnimationInstruction animationInstruction = new PivotHeadersControl.AnimationInstruction(num, num2);
						animationInstruction._width = this.GetItemWidth(num);
						if (animationInstruction._width > 0.0)
						{
							this._queuedAnimations.Enqueue(animationInstruction);
						}
					}
					this.UpdateActiveAndQueuedAnimations();
				}
				else
				{
					if (this._queuedAnimations.get_Count() == 0 && !this._isAnimating)
					{
						this.BeginAnimateInternal(previousIndex, newIndex, this.QuarticEase, default(Duration?));
						return;
					}
					PivotHeadersControl.AnimationInstruction animationInstruction2 = new PivotHeadersControl.AnimationInstruction(previousIndex, newIndex);
					animationInstruction2._ease = this.QuarticEase;
					animationInstruction2._width = this.GetItemWidth(previousIndex);
					this._queuedAnimations.Enqueue(animationInstruction2);
					this.UpdateActiveAndQueuedAnimations();
				}
				if (!this._isAnimating)
				{
					this.AnimateComplete();
				}
				return;
			}
			this.VisualFirstIndex = newIndex;
		}
		private void UpdateActiveAndQueuedAnimations()
		{
			TransformAnimator.EnsureAnimator(this._canvas, ref this._canvasAnimator);
			if (this._canvasAnimator == null)
			{
				return;
			}
			double num = 0.0;
			using (Queue<PivotHeadersControl.AnimationInstruction>.Enumerator enumerator = this._queuedAnimations.GetEnumerator())
			{
				while (enumerator.MoveNext())
				{
					PivotHeadersControl.AnimationInstruction current = enumerator.get_Current();
					num += current._width;
				}
			}
			if (this._isAnimating && this._animatingWidth > 0.0)
			{
				num += this._animatingWidth;
			}
			int num2 = 0;
			using (Queue<PivotHeadersControl.AnimationInstruction>.Enumerator enumerator2 = this._queuedAnimations.GetEnumerator())
			{
				while (enumerator2.MoveNext())
				{
					PivotHeadersControl.AnimationInstruction current2 = enumerator2.get_Current();
					num2++;
					current2._durationInSeconds = current2._width / ((num == 0.0) ? 1.0 : num) * 0.5;
					current2._ease = ((num2 == this._queuedAnimations.get_Count()) ? this.QuarticEase : null);
					if (this._isAnimating)
					{
						this._canvasAnimator.UpdateEasingFunction(null);
					}
				}
			}
			if (this._isAnimating)
			{
				double totalSeconds = (DateTime.get_Now() - this._currentItemAnimationStarted).get_TotalSeconds();
				double num3 = totalSeconds / 0.5;
				double num4 = this._animatingWidth * num3 / ((num == 0.0) ? 1.0 : num);
				this._canvasAnimator.UpdateDuration(new Duration(TimeSpan.FromSeconds(num4 * num3 * 0.5)));
			}
		}
		private void BeginAnimateInternal(int previousIndex, int newIndex, IEasingFunction ease, Duration? optionalDuration)
		{
			if (previousIndex == newIndex || previousIndex < 0 || previousIndex >= base.get_Items().get_Count() || this._isDesign || this._canvas == null)
			{
				if (this.VisualFirstIndex != newIndex)
				{
					this.VisualFirstIndex = newIndex;
				}
				this.AnimateComplete();
				return;
			}
			TransformAnimator.EnsureAnimator(this._canvas, ref this._canvasAnimator);
			this._isAnimating = true;
			bool flag;
			int index = (flag = ((base.get_Items().get_Count() != 2) ? (newIndex == this.RollingIncrement(previousIndex)) : (this.AnimationDirection == AnimationDirection.Left))) ? previousIndex : newIndex;
			double itemWidth = this.GetItemWidth(index);
			this._animatingWidth = itemWidth;
			this._currentItemAnimationStarted = DateTime.get_Now();
			double targetOffset = -itemWidth + (flag ? 0.0 : this._canvasAnimator.CurrentOffset);
			double num = (itemWidth == 0.0) ? itemWidth : ((itemWidth - Math.Abs(this._canvasAnimator.CurrentOffset)) / itemWidth);
			if (num == 0.0)
			{
				num = 1.0;
			}
			Duration currentSampleDuration = optionalDuration.get_HasValue() ? optionalDuration.get_Value() : new Duration(TimeSpan.FromSeconds(0.25 + Math.Abs(num * 0.25)));
			if (flag)
			{
				this._canvasAnimator.GoTo(targetOffset, currentSampleDuration, ease, delegate
				{
					this.VisualFirstIndex = newIndex;
					this._canvasAnimator.GoTo(0.0, Pivot.ZeroDuration, new Action(this.AnimateComplete));
				});
				return;
			}
			this.VisualFirstIndex = newIndex;
			this._canvasAnimator.GoTo(targetOffset, Pivot.ZeroDuration, delegate
			{
				this._canvasAnimator.GoTo(0.0, currentSampleDuration, ease, new Action(this.AnimateComplete));
			});
		}
		private void AnimateComplete()
		{
			if (this._queuedAnimations.get_Count() == 0)
			{
				this._isAnimating = false;
				return;
			}
			PivotHeadersControl.AnimationInstruction animationInstruction = this._queuedAnimations.Dequeue();
			Duration duration = new Duration(TimeSpan.FromSeconds(animationInstruction._durationInSeconds));
			this.BeginAnimateInternal(animationInstruction._previousIndex, animationInstruction._index, animationInstruction._ease, new Duration?(duration));
		}
		private double GetLeftMirrorWidth(int index)
		{
			return this.GetItemWidth(this.GetPreviousVisualIndex(index));
		}
		private double GetNextHeaderWidth()
		{
			int num = this.VisualFirstIndex + 1;
			if (num >= base.get_Items().get_Count())
			{
				num = 0;
			}
			return this.GetItemWidth(num);
		}
		private double GetItemWidth(int index)
		{
			Control control = this.GetItemFromIndex(index) as Control;
			double num = 0.0;
			if (control != null && !this._sizes.TryGetValue(control, ref num))
			{
				num = control.get_ActualWidth();
				if (!double.IsNaN(num))
				{
					this._sizes.set_Item(control, num);
				}
			}
			return num;
		}
		private int GetPreviousVisualIndex(int indexOfInterest)
		{
			int num = indexOfInterest - 1;
			if (num >= 0)
			{
				return num;
			}
			return base.get_Items().get_Count() - 1;
		}
		private void UpdateLeftMirrorImage(int visualRootIndex)
		{
			if (this._leftMirrorTranslation != null && this._sizes != null && this._leftMirror != null)
			{
				if (base.get_Items().get_Count() <= 1)
				{
					this._leftMirror = null;
					return;
				}
				int previousVisualIndex = this.GetPreviousVisualIndex(visualRootIndex);
				PivotHeaderItem pivotHeaderItem = this.GetItemFromIndex(previousVisualIndex) as PivotHeaderItem;
				if (pivotHeaderItem != null && this._sizes.ContainsKey(pivotHeaderItem))
				{
					double num = this._sizes.get_Item(pivotHeaderItem);
					pivotHeaderItem.UpdateVisualStateToUnselected();
					try
					{
						try
						{
							WriteableBitmap source = new WriteableBitmap(pivotHeaderItem, new TranslateTransform());
							this._leftMirror.set_Source(source);
						}
						catch (Exception)
						{
							this._leftMirror.set_Source(null);
						}
						return;
					}
					finally
					{
						pivotHeaderItem.RestoreVisualStates();
						this._leftMirrorTranslation.set_X(-num);
					}
				}
				return;
			}
		}
		private void UpdateItemsLayout()
		{
			int count = base.get_Items().get_Count();
			double num = 0.0;
			int visualFirstIndex = this.VisualFirstIndex;
			for (int i = visualFirstIndex; i < base.get_Items().get_Count(); i++)
			{
				this.FadeInItemIfNeeded(i, visualFirstIndex, this._previousVisualFirstIndex, count);
				this.SetItemPosition(i, ref num);
			}
			if (this.VisualFirstIndex > 0)
			{
				for (int j = 0; j < this.VisualFirstIndex; j++)
				{
					this.FadeInItemIfNeeded(j, visualFirstIndex, this._previousVisualFirstIndex, count);
					this.SetItemPosition(j, ref num);
				}
			}
		}
		private void FadeInItemIfNeeded(int index, int visualFirstIndex, int previousVisualFirstIndex, int itemCount)
		{
			if (!this._isDesign && this.RollingIncrement(index) == visualFirstIndex && index == previousVisualFirstIndex)
			{
				if (itemCount > 1 && (itemCount != 2 || this.AnimationDirection != AnimationDirection.Right))
				{
					double num = 0.0;
					for (int num2 = this.RollingIncrement(index); num2 != index; num2 = this.RollingIncrement(num2))
					{
						num += this.GetItemWidth(num2);
					}
					if (num < base.get_ActualWidth())
					{
						this.FadeIn(index);
						return;
					}
				}
			}
			else
			{
				UIElement uIElement = this.GetItemFromIndex(index) as UIElement;
				if (uIElement != null)
				{
					uIElement.set_Opacity(1.0);
				}
			}
		}
		private object GetItemFromIndex(int index)
		{
			if (base.get_Items().get_Count() > index)
			{
				return base.get_Items().get_Item(index);
			}
			return null;
		}
		private int RollingIncrement(int index)
		{
			index++;
			if (index >= base.get_Items().get_Count())
			{
				return 0;
			}
			return index;
		}
		private int RollingDecrement(int index)
		{
			index--;
			if (index >= 0)
			{
				return index;
			}
			return base.get_Items().get_Count() - 1;
		}
		private void FadeIn(int index)
		{
			Control control = (Control)base.get_Items().get_Item(index);
			OpacityAnimator oa;
			if (!this._opacities.TryGetValue(control, ref oa))
			{
				OpacityAnimator.EnsureAnimator(control, ref oa);
				this._opacities.set_Item(control, oa);
			}
			if (oa != null)
			{
				oa.GoTo(0.0, Pivot.ZeroDuration, delegate
				{
					oa.GoTo(1.0, new Duration(TimeSpan.FromSeconds(0.125)));
				});
			}
		}
		private void SetItemPosition(int i, ref double offset)
		{
			Control control = this.GetItemFromIndex(i) as Control;
			if (control != null)
			{
				double num;
				if (!this._sizes.TryGetValue(control, ref num))
				{
					num = 0.0;
				}
				TranslateTransform translateTransform;
				if (!this._translations.TryGetValue(control, ref translateTransform))
				{
					translateTransform = TransformAnimator.GetTranslateTransform(control);
					this._translations.set_Item(control, translateTransform);
				}
				translateTransform.set_X(offset);
				offset += num;
			}
		}
	}
}
